//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#if _MSC_VER > 1000
#pragma once
#endif

#ifndef __CTHREAD_H__
#define __CTHREAD_H__

#include <elasys_server.h>
#include <linknode.h>
#include <interlocked.h>
#include "objenum.h"
#include <aura.h>

class CThread : public ObjectEnumeratorNode, public IThread, public IThreadContext
{
public:
    CARAPI_(IInterface *) GetObject() { return (IThread *)this; }

public:
    CARAPI_(PInterface) Probe(
        /* [in]  */ REIID riid);

    CARAPI_(UInt32) AddRef();

    CARAPI_(UInt32) Release();

    CARAPI Aggregate(
        /* [in] */ AggrType aggrType,
        /* [in] */ PInterface pObject);

    CARAPI GetDomain(
        /* [out] */ PInterface *ppObject);

    CARAPI Start();

    CARAPI Suspend();

    CARAPI Resume();

    CARAPI Join(
        /* [in] */ Millisecond32 timeout,
        /* [out] */ WaitResult *pResult);

    CARAPI Interrupt();

    CARAPI Abort();

    CARAPI SetPriority(
        /* [in] */ ThreadPriority priority);

    CARAPI GetPriority(
        /* [out] */ ThreadPriority * pPriority);

    CARAPI GetId(
        /* [out] */ ThreadId * pTid);

    CARAPI SetName(
        /* [in] */ WString name);

    CARAPI GetName(
        /* [out] */ WStringBuf * pName);

    CARAPI GetState(
        /* [out] */ ThreadState * pState);

    CARAPI GetQuitCode(
        /* [out] */ QuitCode * pQuitCode);

    CARAPI GetStartTime(
        /* [out] */ SystemTime * pTime);

    CARAPI GetQuitTime(
        /* [out] */ SystemTime * pTime);

    CARAPI GetProcessorTimes(
        /* [out] */ Millisecond32 * pUserTime,
        /* [out] */ Millisecond32 * pKernelTime);
        
    CARAPI Quit();

//IThreadContext
    CARAPI GetContext(
        /* [out] */ ArrayOf<Int32> *pContextArray);

    CARAPI SetContext(
        /* [out] */ const ArrayOf<Int32> &contextArray);

    CARAPI GetUserStackTop(
        /* [out] */ Address *pStackTop);

public:
    void DoAtQuit(
        /* [in] */ ECode quitCode,
        /* [in] */ Boolean bCallAbortion);

    ECode GetLocalSlotValue(
        /* [in] */ Int32 index,
        /* [out] */ PVoid * ppValue);

    ECode SetLocalSlotValue(
        /* [in] */ Int32 index,
        /* [in] */ PVoid pValue);

    void TransferInfo(
        /* [in] */ QuitCode quitCode);

    void SetThreadState(
        /* [in] */ ThreadState state);

    void GetUserEntry(
        /* [out] */ Address * pUsrEntry,
        /* [out] */ Address * pUsrArgs);

public:
    STATIC ECode S_Create( // for main thread object.
        /* [in] */ IProcess * pOwner,
        /* [out] */ IThread ** ppThread);

    STATIC ECode S_Create( // for normal thread object.
        /* [in] */ IProcess * pOwner,
        /* [in] */ Address threadMainStartup,
        /* [in] */ Address threadRoutine,
        /* [in] */ Address threadArg,
        /* [in] */ ThreadCreationFlag flags,
        /* [out] */ IThread ** ppThread);

public:
    CThread(IProcess * pOwner, Address userEntry = 0, Address userArgs = 0);
    virtual ~CThread();

private:
    ECode Initialize();              // for normal thread object.
    ECode InitializeAsMainThread();  // for main   thread object.

private:
    ThreadId  m_threadId;
    Aura_Handle    m_hThread;

    Address   m_userEntry;
    Address   m_userArgs;

    IProcess *  m_pOwner;
    PVoid       m_hObjLock;

    ThreadState m_threadState;
    Interlocked m_nestedSuspend;
    QuitCode    m_quitCode;
    SystemTime  m_startTime;
    SystemTime  m_quitTime;

    PVoid       m_hQuitEvent;

    PVoid    m_hTlsLock;
    PVoid    m_tlsValue[TLS_TOTAL_SLOTS];

    WStringBuf_<MAXIMUM_THREAD_NAME_LENGTH> m_name;

private:
    Interlocked  m_Refs;
};

INLINE void CThread::GetUserEntry(
        /* [out] */ Address * pUsrEntry,
        /* [out] */ Address * pUsrArgs)
{
    *pUsrEntry = m_userEntry;
    *pUsrArgs  = m_userArgs;
}

#endif // __CTHREAD_H__
